﻿using Comkarl.Web.Serialization;
using System;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;

namespace Comkarl.Web
{
    public abstract class ServiceProxyHandler : IHttpAsyncHandler
    {
        public bool IsReusable
        {
            get { return true; }
        }

        private Action RequestAction
        {
            get;
            set;
        }

        protected virtual void OnPrepare(HttpContext context)
        {
        }

        protected virtual void OnReceived(HttpContext context, object result)
        {
        }

        public void ProcessRequest(HttpContext context)
        {
            string operationName = context.Request.PathInfo;
            MethodInfo operation = GetType().GetMethod(operationName.TrimStart('/'), BindingFlags.Instance | BindingFlags.NonPublic);

            OnPrepare(context);

            context.Response.Clear();

            string proxyArgs = HttpUtility.UrlDecode(context.Request.Form["proxyArgs"]);
            object result = null;

            Task.WaitAll
            (
                ((Task<object>)operation.Invoke(this, proxyArgs != "null" ? new object[] { JsonSerializer.Current.Deserialize(proxyArgs) } : new object[] { null }))
                    .ContinueWith(task => result = task.Result)
            );

            OnReceived(context, result);

            context.Response.Write(JsonSerializer.Current.Serialize(result));
        }

        public System.IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            RequestAction = () => ProcessRequest(context);

            return RequestAction.BeginInvoke(cb, extraData);
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            RequestAction.EndInvoke(result);
        }
    }
}